/*
 * sysstart.cpp
 *
 *  Created on: 2013-6-14
 *      Author: dylan
 */

#include "sysprocess.h"
#include "tinyxml.h"
#include <iostream>
#include <string>
#include <signal.h>
#include "../../../string_old/inc/u_args.h"
#include "../../../string_old/inc/u_string.h"

using namespace std;

bool sig = false;

int num = 0;
string * program = NULL;
CSysProcess* process = NULL;

void stopAllProcess( int ){
	sig = true;
}

void showHelp( const char* cmd ){
	const char* p = NUString::lastChar(cmd,'/');
	if( p==NULL )
		p = cmd;
	else
		p = p+1;

	cout <<"This command can start other programs, and restart them when any exited.\n"
			<<"You should use this command with the names of other programs with space seprated."
			<<endl;

	cout <<"Help Information for sysstart tools.\n"
			<<"Usage: "<<p<<" [-g] [ -c cfg_file|--config=cfg_file] [cmd1 cmd2 ...] [-h|--help]\n"
			<<"\t -g                generate a config file, which is specialized by cfg_file, default using 'sysstart.sample.xml'\n "
			<<"\t -c|--config=  specializes a config file with a path name by cfg_file.\n"
			<<"\t -h|--help       show this infomation.\n"
			<<"cmds               if no -c or --config= will start the program cmd1,comd2,..."
			<<endl;
}

void genarateConfigFile( const char* fileName ){
	if( fileName==NULL )
		fileName = "sysstart.sample.xml";

	TiXmlDocument doc;
	TiXmlDeclaration* decl = new TiXmlDeclaration("1.0","","");
	doc.LinkEndChild(decl);

	TiXmlElement * root = new TiXmlElement( "SysStart" );
	doc.LinkEndChild(root);

	TiXmlElement * cmd = new TiXmlElement("cmd");
	TiXmlComment* cmt = new TiXmlComment("set up you cmd here");
	cmd->LinkEndChild(cmt);
	root->LinkEndChild(cmd);

	cmd = new TiXmlElement("cmd");
	cmt = new TiXmlComment("set up you cmd here");
	cmd->LinkEndChild(cmt);
	root->LinkEndChild(cmd);

	doc.SaveFile(fileName);
}

bool loadConfigFile( const char* fileName ){
	if( fileName==NULL )
		return false;

	TiXmlDocument doc(fileName);
	TiXmlElement* root;

	if( !doc.LoadFile() || NULL==(root = doc.FirstChildElement("SysStart")) ){
		cout <<"There are some errors in the config file "<<fileName<<endl;
		return false;
	}

	TiXmlElement* cmd = root->FirstChildElement("cmd");
	while( cmd!=NULL ){
		if( NULL!=cmd->GetText() )
			++num;
		cmd = root->NextSiblingElement("cmd");
	}

	if( num==0 ){
		cout <<"No configure in the config file "<<fileName<<endl;
		return false;
	}

	process = new CSysProcess[num];
	program = new string[num];

	root = doc.FirstChildElement("SysStart");
	cmd = root->FirstChildElement("cmd");
	int i = 0;
	while( cmd!=NULL ){
		if( NULL!=cmd->GetText() ){
			program[i] = cmd->GetText();
			++i;
		}

		cmd = root->NextSiblingElement("cmd");
	}

	return true;
}

int main( int argc,char* argv [] ){
	int i;

	if( argc==1 || NUString::checkOpt(argc,argv,"-h")||NUString::checkOpt(argc,argv,"--help")){
		showHelp(argv[0]);
		return 0;
	}

	signal(SIGINT,stopAllProcess );
	signal(SIGTERM,stopAllProcess );

	const char* cfg = NUString::getOptValue(argc,argv,"-c","--config=");
	if( NUString::checkOpt(argc,argv,"-g") ){
		// 产生配置文件示例
		genarateConfigFile(cfg);
		return 0;
	}

	if( cfg!=NULL ){
		if( !loadConfigFile(cfg) ){
			cout <<"load config file fail."<<endl;
			return 1;
		}
	}else{
		num = argc -1 ;
		program = new string[num];
		process = new CSysProcess[num];

		for( i=0;i<num;++i ){
			program[i] = argv[i+1];
		}
	}

	while( !sig ){
//		sleep(5);
		for( i=0;i<num;++i ){
			if( !sig && !process[i].ifRunning() ){
				cout <<"Starting program "<<program[i]<<":"<<process[i].exec(program[i].c_str() )<<endl;
			}
		}
	}

	if( num>0 ){
		cout <<"Now Stopping All Processes..."<<endl;

		bool hasRun = true;

		while( hasRun ){
			hasRun = false;
			for( i=0;i<num;i++ ){
				cout <<"Checking program "<<program[i]<<endl;
				if( process[i].ifRunning() ){
					hasRun = true;
					process[i].stop();
					cout <<" Stopping program "<<program[i]<<"... "<<endl;
				}
			}

			if( hasRun ){
				cout <<"waitting program stop..."<<endl;
//				sleep(1);
			}
		}

		delete [] process;
		delete [] program;
	}

	cout <<" Processes Stopped, and Now Exit"<<endl;

	return 0;
}
